import { TYPES, rpxToPx, conversionUnit } from './util'
import Draw from './draw'
import getModeImage from './images'
import { getImageInfo } from './images'
export default class Poster extends Draw {

	constructor(params) {
		super()
		this.paramsInit(params)
	}

	/**
	 * 转换单位
	 * @param { Object | Array } params 参数
	 * @returns 
	 */
	conversionUnit(params) {
		return conversionUnit(params, this.getUnit, this)
	}

	/**
	 * 参数初始化
	 * @param { Object } params 绘制参数
	 */
	paramsInit(params) {
		const { 
			width = 375.0001, height, background, canvasId = null, type = 'default', unit = 'px', 
			drawDelayTime = 200, delayTime = 200, fileType = 'png', quality = 1, 
			isCompressImage = false, success = () => {}, _this = null, drawTipsText = '绘制中...'
		} = params
		this.width = width
		this.height = height
		// canvas背景
		this.background = background || {
			type: 'color',
			w: width,
			h: height,
			color: '#ffffff'
		}
		// canvas-id
		this.canvasId = canvasId
		// 绘制类型
		this.type = type
		// 绘制单位
		this.unit = unit
		// 绘制图片延迟
		this.drawDelayTime = drawDelayTime
		// 生成图片延迟
		this.delayTime = delayTime
		// 导出图片类型
		this.fileType = fileType
		// 导出图片的质量
		this.quality = quality
		// 是否压缩图片
		this.isCompressImage = isCompressImage
		// 当2d绘制时的回调
		this.success = success
		// 页面this对象
		this._this = _this
		// canvas绘制对象
		this.Context = null
		// canvas对象
		this.canvas = null
		this.drawTipsText = drawTipsText
		// 获取绘制对象
		this.getContext()

		// 绘制时的参数
		this.canvasWidth = this.getUnit(width)
		this.canvasHeight = this.getUnit(height)
		this.callback = {
			bgObj: {
				width: this.background.w,
				height: this.background.h
			},
			ctxObj: {
				width,
				height
			},
			style: {
				width: this.canvasWidth + 'px',
				height: this.canvasHeight + 'px'
			}
		}
		this.allCallback = []
		this.drawArray = null
	}

	/**
	 * 获取转换的单位
	 * @param { Number } size 尺寸大小
	 * @returns 
	 */
	getUnit(size) {
		const { unit } = this
		if (typeof size === 'undefined' || typeof size === 'null') {
			return 0
		}
		if(unit == 'px') {
			return size
		}
		if (typeof size === 'number') { 
			// console.log('width', size)
			return size === 375.0001 ? 375.0001 : uni.upx2px(size)
		}
		if (typeof size === 'string') {
			return rpxToPx(size)
		}
	}

	/**
	 * 获取绘制对象
	 */
	getContext() {
		const { width, height, canvasId, _this, type, success } = this
		if (!TYPES.includes(type)) {
			this.Context = uni.createCanvasContext(canvasId, _this)
			return
		}
		const query = uni.createSelectorQuery().in(_this)
		query.select(`#${canvasId}`)
		.fields({ node: true, size: true })
		.exec(res => {
			const canvas = res[0].node
			this.Context = canvas.getContext(type)
			const dpr = uni.getSystemInfoSync().pixelRatio
			canvas.width = this.getUnit(width) * dpr
			canvas.height = this.getUnit(height) * dpr
			this.canvas = canvas
			this.Context.scale(dpr, dpr)
			// this.width = width * dpr
			// this.height = height * dpr
			// console.log('width', this.width)
			// console.log('height', this.height)
			if (success != undefined && typeof success === 'function') {
				success()
			}
		})
	}

	/**
	 * 获取绘制参数
	 * @param { Object } params 参数
	 * @param { String } type 参数类别
	 * @param { Object } conversion 是否转换单位默认true
	 */
	getDrawParams(params, type, conversion = true) {
		const { width } = this
		const { x = 0, y = 0, w = width, h = 0, r = 0, color = 'black', alpha = 1, isFill = true, 
			lineWidth = 1, windowAlign = 'none', rotate = {}, drawImage = false, 
			borderColor = '#000000', borderWidth = 0, borderType = 'default', offsetRight = 0,
			shadow, gradient = {},
		} = params
		const drawParams = { x, y, w, h, r }
		// 公共的参数
		const globalData = {
			...drawParams,
			color,
			lineWidth,
			borderWidth,
			borderColor,
			borderType,
			alpha,
			isFill,
			// 窗口对齐的方式 默认: none 可选 居中: center 右边: right
			windowAlign,
			// 旋转
			rotate,
			// 阴影
			shadow: this.conversionUnit(this.getShadow(shadow)),
			// 渐变
			gradient,
			// 距离右边的差值
			offsetRight,
			drawImage
		}
		// 绘制圆的参数
		const { s = 0, e = Math.PI * 2, d = false } = params
		const arcParams = {
			s,
			e,
			d,
			// 是否是在绘制图片,默认不是
			drawImage,
		}
		// 绘制三角形的参数
		const { coordinate = [], drawType = 'isosceles', direction = 'top' } = params
		const triangleParams = {
			// 当绘制类别是自定义的时候需要传递的参数
			coordinate,
			// 绘制三角形的类型
			// right: 直角三角形
			// isosceles: 等腰三角形
			// custom: 自定义时，x, y, 宽, 高都不需要传递。需要传递绘制点的坐标类型是数组(coordinate)
			// [[1, 3], [2, 3], [4, 5]]
			drawType,
			// 三角形顶点朝向 top, left, right, bottom
			direction,
		}
		// 绘制图片的参数
		const { 
			src = '', mode = 'aspectFill', triangle = {}, isCompressImage = false, 
			quality = 100, drawSrc = false, drawModeImage = false, drawImageInfo = false 
		} = params
		const imageParams = {
			src,
			mode,
			drawType: params.drawType || 'default',
			// 绘制三角形图片时三角形的内容
			// triangle.type 三角形的类型 right: 直角三角形 isosceles: 等腰三角形 custom: 自定义三角形(不支持旋转)
			// triangle.coordinate 自定义三角形时传递的坐标
			// triangle.direction 三角形顶点朝向
			triangle,
			// 是否压缩图片
			isCompressImage,
			// 压缩图片时图片的质量只对jpg类型的图片生效
			quality,
			drawSrc,
			drawModeImage,
			drawImageInfo,
			drawImage: true
		}
		// 绘制文字的参数
		const { 
			text = '', textIndent = 0, lastWidth = 0, font = {}, 
			textAlign = 'none', baseline = 'top', line = {}, 
			highlightText = [], textRect = { show: false, isFill: true, lineWidth: 1 }
		} = params
		const textParams = {
			text: String(text) || '',
			textIndent,
			lastWidth,
			font: conversion ? this.conversionUnit(this.getFont(font)) : this.getFont(font, conversion),
			textAlign,
			baseline,
			line: this.getTextLine(line, conversion),
			highlightText,
			textRect,
			h
		}
		// 绘制线的参数
		const { algin = 'right', lineType = 'solid', pattern = [6, 6], offset = 6, lineCap = 'butt' } = params
		const lineParams = {
			algin,
			// dashed 虚线 solid 实线
			lineType,
			// 详看CanvasContext.setLineDash文档
			// 一组描述交替绘制线段和间距（坐标空间单位）长度的数字
			pattern,
			// 虚线偏移量
			offset,
			lineCap
		}
		// 绘制二维码的参数
		const { image = {}, size = 100, lv = 3, background = '#ffffff', foreground = '#000000', pdground = '#000000' } = params
		const qrCodeParams = {
			text: String(text) || '',
			image,
			size,
			// 容错级别 默认3
			correctLevel: lv,
			// 二维码背景色
			background,
			// 二维码前景色
			foreground,
			// 二维码角标色
			pdground,
		}
		const getParams = () => {
			switch(type) {
				// 矩形
				case 'rect':
					return globalData
				// 圆形
				case 'arc':
					return { ...globalData, ...arcParams}
				// 三角形
				case 'triangle':
					return { ...globalData, ...triangleParams }
				// 图片
				case 'image':
					return { ...globalData, ...imageParams }
				// 文字
				case 'text':
					return { ...globalData, ...textParams }
				// 线
				case 'line':
					return { ...globalData, ...lineParams }
				// 二维码
				case 'qrcode':
					return { ...globalData, ...qrCodeParams }
				default:
					return globalData
			}
		}
		return conversion ? this.conversionUnit(getParams()) : getParams()
	}

	/**
	 * 排序drawArray 根据数据的zIndex进行排序，修改渲染顺序
	 * @param { Array } drawArray 绘制内容
	 */
	sortDrawArray(drawArray = []) {
		return drawArray.sort((after, current) => {
			const aZIndex = after.zIndex || 0
			const cZIndex = current.zIndex || 0
			return aZIndex - cZIndex
		})
	}

	/**
	 * 往所有的回调信息里面添加内容
	 * @param { Object } params 内容
	 */
	async setAllCallBack(params) {
		const { width, canvasWidth } = this
		let { 
			type, x = 0, y = 0, r = 0, w = canvasWidth, h = 0, 
			lineWidth = 1, size = 0, name = '', windowAlign = 'none', 
			drawType = 'default', mode = 'aspectFill', src = '', offsetRight
		} = params
		let sx = x
		let sy = y
		let ex = x + w
		let ey = y + h
		// 文字
		if (type === 'text') {
			let { 
				text, textIndent, lastWidth, font, line, textAlign, windowAlign, color 
			} = this.getDrawParams(params, 'text', false)
			const textArr = this.computedFontTextLineHeight(x, y, w, text, textIndent, lastWidth, font, line, textAlign, windowAlign, color)
			const lastText = textArr[textArr.length - 1]
			const firstText = textArr[0]
			ey = lastText.ey
			ex = firstText.tx + firstText.w
			params.textArr = this.conversionUnit(textArr)
			params.h = ey - sy
			params.tw = firstText.w
			// if (params.name) {
			// 	console.log(params.text)
			// 	console.log(font)
			// 	console.log(textArr)
			// }
		}
		// 圆形
		if (type === 'arc') {
			ex = x + r * 2
			ey = y + r * 2
			w = r * 2
			h = r * 2
		}
		// 线
		if (type === 'line') {
			ey = y + lineWidth
			h = lineWidth
		}
		// 二维码
		if (type === 'qrcode') {
			ex = x + size
			ey = y + size
			w = size
			h = size
		}
		// 图片
		if (type == 'image') {
			if (windowAlign != 'none') {
				x = this.computedCenterX(width, w, windowAlign, offsetRight)
			}
			const srcRes = await this.getImageSrc(src)
			if (!srcRes.success) {
				return srcRes
			}
			src = srcRes.src
			const imageInfo = await getImageInfo(src)
			if (!imageInfo.success) {
				uni.hideLoading()
				return Promise.resolve(true)
			}
			
			const modeImage = getModeImage(Number(imageInfo.width), Number(imageInfo.height), this.getUnit(x), this.getUnit(y), this.getUnit(w), this.getUnit(h), mode)
			const { dx, dy, dw, dh, sw, sh, sx, sy } = modeImage
			if (mode == 'widthFix') {
				h = sh
				ey = y + h
			}
			if (mode == 'heightFix') {
				w = sw
				ex = x + w
			}
			if (drawType == 'arc' && h == 0) {
				h = w
				ey = y + h
			}
			params.drawModeImage = modeImage
			params.drawSrc = src
			params.drawImageInfo = imageInfo
		}
		params.sx = sx
		params.sy = sy
		params.ex = ex
		params.ey = ey
		// console.log({
		// 	sx,
		// 	sy,
		// 	ex,
		// 	ey,
		// 	w,
		// 	h
		// })
		this.allCallback.push({
			sx,
			sy,
			ex,
			ey,
			w,
			h,
			name,
			before: params.before || {}
		})
		return Promise.resolve(true)
	}

	/**
	 * 绘制背景
	 * @returns 
	 */
	drawBackground() {
		const { background, width, height, Context } = this
		return new Promise(async resolve => {
			const { type, ...params } = background
			Context.beginPath()
			Context.save()
			// 绘制背景色
			if (type == 'color') {
				this.drawRect({
					...params,
					w: params.w || width,
					h: params.h || height,
					color: params.color || '#ffffff'
				})
			}
			// 绘制背景图
			if (type == 'image') {
				await this.drawImage({
					...params,
					w: params.w || width,
					h: params.h || height,
				})
			}
			Context.clip()
			Context.restore()
			resolve({
				success: true
			})
		})
	}

	/**
	 * 绘制内容
	 * @returns 
	 */
	drawCanvas(drawArray) {
		const { Context } = this
		return new Promise(async resolve => {
			try {
				for (let i of drawArray) {
					if (i.callback && typeof i.callback == 'function' && i.type != 'custom') {
						// console.log('Jinru ')
						const beforeInfo = this.allCallback.length == 0 ? {} : this.allCallback[this.allCallback.length - 1]
						const callBackInfo = i.callback(beforeInfo, this.allCallback) || {}
						const { callback, ...data } = i
						i = { ...data, ...callBackInfo }
					}
					if (i.callBack && typeof i.callBack == 'function' && i.type != 'custom') {
						// console.log('Jinru ')
						const beforeInfo = this.allCallback.length == 0 ? {} : this.allCallback[this.allCallback.length - 1]
						const callBackInfo = i.callBack(beforeInfo, this.allCallback) || {}
						const { callBack, ...data } = i
						i = { ...data, ...callBackInfo }
					}
					if (i.type != 'custom' && i.drawType != 'custom') {
						await this.setAllCallBack(i)
					}
					console.log(i.type);
					switch (i.type) {
						// 文字
						case 'text': 
							this.drawText(i)
							break
						// 矩形
						case 'rect':
							this.drawRect(i)
							break
						// 图片
						case 'image': 
							const image = await this.drawImage(i)
							console.log(image);
							if (!image.success) {
								return resolve(image)
							}
							break
						// 圆形
						case 'arc':
							this.drawArc(i)
							break
						// 三角形
						case 'triangle':
							this.drawTriangle(i)
							break
						// 线条
						case 'line':
							this.drawLine(i)
							break
						// 二维码
						case 'qrcode':
							await this.drawQrCode(i)
							break
						// 自定义
						case 'custom':
							i.setDarw(Context, this)
							break
					}
				}
				resolve({
					success: true
				})
			} catch(e) {
				uni.hideLoading()
				return resolve({
					success: false,
					msg: '绘制内容失败:' + e
				})
			}
		})
	}

	/**
	 * 导出图片
	 * @returns 
	 */
	exportImage() {
		const { delayTime } = this
		return new Promise(resolve => {
			uni.showLoading({ title: '导出图片中...' })
			// 绘制图片
			setTimeout(async () => {
				resolve(await this.createCanvasFilePath())
				uni.hideLoading()
			}, delayTime || 200)
		})
	}

	/**
	 * 创建canvas导出文件
	 * @returns 
	 */
	createCanvasFilePath() {
		let { canvas, canvasId, width, height, _this, fileType, quality, type } = this
		if (type === '2d') {
			const dpr = uni.getSystemInfoSync().pixelRatio
			width = width * dpr
			height = height * dpr
		}
		return new Promise(resolve => {
			try {
				uni.canvasToTempFilePath({
					canvasId,
					canvas,
					x: 0,
					y: 0,
					width,
					height,
					quality,
					fileType,
					success: res => {
						return resolve({
							success: true,
							data: res.tempFilePath,
							msg: '绘画成功'
						})
					},
					fail: err => {
						uni.hideLoading()
						return resolve({
							success: false,
							msg: `导出图片失败: ${JSON.stringify(err)}`
						})
					}
				}, _this || null)
			} catch (e) {
				uni.hideLoading()
				return resolve({
					success: false,
					msg: '导出图片失败: 绘画错误' + e
				})
			}
		})
	}

	/**
	 * 将绘制的内容绘制到画布上
	 * @returns 
	 */
	canvasDraw() {
		const { Context, drawDelayTime, type } = this
		return new Promise(async resolve => {
			setTimeout(async () => {
				uni.hideLoading()
				if (TYPES.includes(type)) {
					return resolve(await this.exportImage())
				} else {
					await Context.draw(true, async () => {
						return resolve(await this.exportImage())
					})
				}
			}, drawDelayTime || 200)
		})
	}

	/**
	 * 创建绘制海报
	 * @param { Function } drawArray 绘制内容 返回一个数组
	 * @returns 
	 */
	createPoster(drawArray) {
		const { callback, drawTipsText } = this
		return new Promise(async resolve => {
			if (drawArray == null || drawArray == undefined) {
				return resolve({
					success: false,
					msg: '请传递绘制内容'
				})
			}
			const backgroundRes = await this.drawBackground()
			if (!backgroundRes.success) {
				return resolve(backgroundRes)
			}
			this.drawArray = drawArray
			uni.showLoading({ title: drawTipsText })
			const result = await this.drawCanvas(this.sortDrawArray(this.drawArray(callback)))
			// 绘制内容
			if (!result.success) {
				uni.hideLoading()
				return resolve(result)
			}
			return resolve(await this.canvasDraw())
		})
	}

	/**
	 * 创建绘制海报 兼容老版本
	 * @param { Function } drawArray 绘制内容 返回一个数组
	 * @returns 
	 */
	createdSharePoster(drawArray) {
		return this.createPoster(drawArray)
	}

}